from __future__ import absolute_import, unicode_literals
import json
import time
import requests
import hashlib
from core.tools.custom_requests import CustomRequests
from hashlib import sha256
import hmac
import base64
import rsa
from core.tools.func_utils import FuncUtils
from core.tools.encryption import hashlib_md5
from urllib import parse
from Crypto.Cipher import AES
from Crypto.Cipher import DES3
from Crypto.Cipher import DES

funcUtils = FuncUtils()


class BaseClient(CustomRequests):
    @property
    def get_private_key(self):
        private_key = getattr(self, "private_key", None)
        if private_key:
            return private_key
        else:
            raise Exception("没有配置应用私钥")

    @property
    def get_public_key(self):
        private_key = getattr(self, "public_key", None)
        if private_key:
            return private_key
        else:
            raise Exception("没有配置应用公钥")

    def get_public(self):
        params = {
            "appId": getattr(self, "appId"),
            "appType": "ZHB",
            "appSecret": getattr(self, "appSecret"),
            "timestamp": str(int(time.time() * 1000)),
            "version": getattr(self, "version"),
            "businessDataEncryptType": getattr(self, "businessDataEncryptType"),
        }
        return params

    def pad(self, s):
        bs = DES3.block_size
        bw = bs - len(s) % bs
        if bw != 8:
            # 每8位一组，不足8位需要补位。
            return s + (bs - len(s) % bs) * chr(bs - len(s) % bs)
        else:
            return s

    def init_str(self, s):
        l = len(s) % 16
        if l != 0:
            c = 16 - l
            s += chr(c) * c
        return s

    def create_key(self, sk):
        r = hashlib.md5(sk).digest()
        return r

    def des_encrypt(self, source):
        """
        :param source: 要加密的内容
        :return:
        """
        appSecret = getattr(self, "appSecret")
        source = json.dumps(source)
        key = self.create_key(appSecret.encode())
        text = self.init_str(source)
        cryptor = DES3.new(key, DES3.MODE_CBC)
        ciphertext = cryptor.encrypt(text.encode())
        b2bencryptkey = base64.standard_b64encode(ciphertext)  # DES加密后的内容
        return b2bencryptkey

    def a1(self, source):
        b2bencryptkey = self.des_encrypt(source)
        public_params = self.get_public()
        public_params["businessData"] = b2bencryptkey

    def sign_with_rsa(self, content):
        """
        六、用私钥对 md5 串进行加密处理得到密文信息。
        七、对密文进行 Base64 处理，拿到 Base64 处理后的串对接口参数 sign 赋值，并对 signType 赋值 RSA。
        :param content:
        :return:
        """
        signature = rsa.sign(content, rsa.PrivateKey.load_pkcs1(self.get_private_key, format='PEM'), 'SHA-1')
        sign = base64.b64encode(signature).decode('utf-8')
        return sign

    def get_sign(self, all_params):
        sign_content_md5_upper = self.get_sign_base64_data(all_params)
        sign = self.sign_with_rsa(sign_content_md5_upper)  # 通过私钥签名
        return sign

    # 第一步：拼接待签数据字符串
    def get_sign_base64_data(self, all_params):
        # 1、将请求报文msgBody中的所有字段提取出来为集合M；
        # 2、将集合M内非空参数值的参数按照参数名ASCII码从小到大进行排序（字典序）（注：去除参数中的所有空格）
        # 3、对参数值（非空）进行encodingURIComponent编码；
        # 4、使用URL键值对的格式（即key1=value1&key2=value2…）将参数名与参数值拼接成字符串stringA；
        sign_content = self.get_sign_content(all_params)
        # 5、对stringA进行MD5处理生成stringB，将stringB转换成全大写字符串stringC；
        sign_md5_upper = hashlib_md5(sign_content).upper()
        # 6、将stringC进行base64编码后作为待签名字符串stringD。
        sign_content_md5_upper = base64.b64encode(sign_md5_upper.encode("utf-8"))
        return sign_content_md5_upper

    def get_sign_md5_lower(self, all_params):
        """
        五、对以上字符串做 md5 处理，处理后得到 32 位的字符串（小写）
        :param all_params:
        :return:
        """
        sign_content = self.get_sign_text(all_params)
        sign_md5 = hashlib_md5(sign_content)
        sign_md5_upper = sign_md5.lower()
        return sign_md5_upper

    @classmethod
    def get_sign_text(cls, all_params):
        """
        四、排序然后用&连接起来
        :param all_params:
        :return:
        """
        s = sorted(all_params.items(), key=lambda kv: (kv[0], kv[1]))
        sign_content = parse.urlencode(s)
        return sign_content

    # 还不知道什么验签呢
    def verify_with_rsa(self, message, sign):
        from Crypto.Hash import SHA
        from Crypto.Signature import PKCS1_v1_5
        from Crypto.PublicKey import RSA
        sign_content_md5_upper = self.get_sign_base64_data(message)
        sign = base64.b64decode(sign)
        publickey = RSA.importKey(self.get_public_key)
        verifier = PKCS1_v1_5.new(publickey)
        return bool(verifier.verify(SHA.new(sign_content_md5_upper), sign))
